#ifndef xpack_net_private_define
#define xpack_net_private_define
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::net_private_define::inc
#include"define/base_type.hpp"
#include"lang/cxx/clone.hpp"
#include"lang/cxx.hpp"
#include"macro/xdefer.hpp"
#include"macro/xstruct.hpp"
#include"memop/swap.hpp"
#pragma pop_macro("xuser")

namespace mixc::net_private_define::origin{
    enum class reuse_address_t{
        disable,
        enable,
        system_default,
    };

    enum class sock_type_t : uxx{
        ipv4_stream,
        ipv6_stream,
        ipv4_dgram,
        ipv6_dgram,

        not_exist = ::not_exist
    };

    struct ipv4_cstr;

    xstruct(
        xname(ipv4),
        xpubf(segment, u08[4]) // 默认为大端编码
    )
        using final_t = the_t;
    public:
        xprops()
            xpubgetx(net_form, u32){
                xr{ return *u32p(xthe.segment); }
            };

            xpubgetx(local_form, u32){
                xr{ return u32(xthe.segment[0]) << 24 | u32(xthe.segment[1]) << 16 | u32(xthe.segment[2]) <<  8 | u32(xthe.segment[3]) <<  0; }
            };

            xpubgetx(is_valid_mask, bool){
                xr{
                    u32 mask            = xthe->local_form;
                    u32 keep_lsb        = mask & (~mask + 1);
                    u32 fill_low_mask   = keep_lsb - 1;
                    u32 full            = mask | fill_low_mask;
                    return ~full == 0;
                }
            };
        $

        xprops_operator()

    public:
        constexpr ipv4() : segment{ 0xff, 0xff, 0xff, 0xff}  {}
        ipv4(asciis ip) : ipv4(inc::c08{ip}){}

        template<class ... u08_t>
        requires(sizeof...(u08_t) == 4)
        ipv4(u08_t const & ... value) : 
            segment{ u08(value)... }{
        }

        ipv4(inc::c08 const & ip, bstate_t * result = nullptr) : ipv4(){
            auto i              = uxx(0);
            auto j              = uxx(0);
            auto v              = uxx(0);
            auto state          = bstate_t::fail;
            uxx  temp[4]        = {};

            xdefer{
                if (result){
                    result[0]   = state;
                }
            };

            for(; i < 4; temp[i] = v, i++){
                for(v = 0; j < ip->length;){
                    if (auto c = ip[j]; '0' <= c and c <= '9'){
                        v       = v * 10 + c - '0';
                        j      += 1;
                        continue;
                    }
                    else if (c != '.'){
                        return;
                    }

                    // 4 个 segment，只需 3 个 '.' 分隔
                    if (j += 1; i != 3){
                        break;
                    }
                    else{
                        return;
                    }
                }
            }

            for(uxx i = 0; i < 4; i++){
                if (temp[i] > 255){
                    return;
                }
            }

            for(uxx i = 0; i < 4; i++){
                segment[i]      = temp[i];
            }

            state               = bstate_t::success;
        }

        operator ipv4_cstr() const;

        the_t & from_net(u32 big_endian){
            *u32p(segment) = big_endian;
            return xthe;
        }

        the_t & from_local(u32 value){
            segment[0] = u08(value >> 24);
            segment[1] = u08(value >> 16);
            segment[2] = u08(value >>  8);
            segment[3] = u08(value >>  0);
            return xthe;
        }

        the_t & operator=(asciis ip){
            *this               = ipv4{ ip };
            return xthe;
        }

        the_t & operator=(inc::c08 const & ip){
            *this               = ipv4{ ip };
            return xthe;
        }
    $

    xstruct(
        xname(ipv4_cstr),
        xpubf(value, char[16])
    )
        constexpr ipv4_cstr() :
            value{ '2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5', '\0' }{
        }

        ipv4_cstr(inc::c08 const & value) : 
            ipv4_cstr() {

            value.clone([&](uxx length){
                this->value[length] = '\0';
                return this->value;
            });
        }

        operator asciis() const {
            return value;
        }
    $

    inline ipv4::operator ipv4_cstr() const {
        auto result                 = ipv4_cstr{};

        for(uxx i = 0, j = 0;;){
            uxx k                   = j;
            uxx value               = segment[i];
            
            do{
                auto v              = '0' + value % 10;
                value              /= 10;
                result.value[j++]   = v;
            }while(value);

            for(uxx ii = 0, length = j - k; ii < length / 2; ii++){
                inc::swap(
                    xmodify(result.value[j - ii - 1]),
                    xmodify(result.value[k + ii])
                );
            }

            if (++i != 4){
                result.value[j++]   = '.';
            }
            else{
                result.value[j]     = '\0';
                return result;
            }
        }
    }

    struct ipv6{
        // u08 
    };

    xstruct(
        xname(port),
        xprof(m_port, u08[2])
    )
        xprops()
            xpubgetx(net_form, u16){
                xr{ return *u16p(xthe.m_port); }
            };

            xpubgetx(local_form, u16){
                xr{ return xthe.m_port[0] << 8 | xthe.m_port[1]; }
            };
        $

        xprops_operator()
    public:
        constexpr port() : m_port(){}
    public:

        the_t & from_net(u16 big_endian){
            *u16p(m_port)           = big_endian;
            return xthe;
        }

        the_t & from_local(u16 value){
            m_port[0]               = (value >> 8) & 0xff;
            m_port[1]               = (value >> 0) & 0xff;
            return xthe;
        }
    $

    xstruct(
        xname(ip_port_pair_v4),
        xprof(m_ip, ipv4),
        xprof(m_port, mixc::net_private_define::origin::port)
    )
        xprops()
            xpubget_pubsetx(ip, ipv4){
                xr{ return xthe.m_ip; }
                xw{ xthe.m_ip = value; }

                xprops_operator_plus(xthe.m_ip)
            };

            xpubget_pubsetx(port, mixc::net_private_define::origin::port){
                xr{ return xthe.m_port; }
                xw{ xthe.m_port = value; }

                xprops_operator_plus(xthe.m_port)
            };

            xpubgetx(ip_cstr, ipv4_cstr){
                xr{ return xthe.m_ip; }
            };
        $

        xprops_operator()

        constexpr ip_port_pair_v4() : m_ip(), m_port() {}
    $
}

#endif

xexport_space(mixc::net_private_define::origin)
